package com.jf.docsify.config;

import java.io.File;
import java.util.List;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import com.jf.docsify.common.exception.DocsifyException;
import com.jf.docsify.common.init.db.DbInit;
import com.jf.docsify.common.utils.AssertUtil;
import com.jf.docsify.common.utils.FileUtil;
import com.jf.docsify.common.utils.SecurityUtil;
import com.jf.docsify.common.utils.SystemUtil;
import com.jf.docsify.handler.MdUrlRewriteHandler;
import com.jf.docsify.interceptor.AuthInterceptor;
import com.jf.docsify.interceptor.ErrorInterceptor;
import com.jf.docsify.modules.model.Organization;
import com.jf.docsify.modules.model.SysUser;
import com.jf.docsify.modules.model._MappingKit;
import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.config.JFinalConfig;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.ext.handler.UrlSkipHandler;
import com.jfinal.json.FastJsonFactory;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.ehcache.EhCachePlugin;
import com.jfinal.template.Engine;

/**
 * Description: 配置文件
 *
 * @author chenwr
 * @version 1.0
 *
 * <pre>
 * 修改记录:
 * 修改后版本           修改人       修改日期         修改内容
 * 2022/7/25.1       chenwr    2022/7/25           Create
 * </pre>
 * @date 2022/7/25
 */
public class DocsifyConfig extends JFinalConfig {

    public static String defaultPath = null;

    public static String superAdminUserName = null;

    public static String gitDefaultFolderName = "content";

    @Override
    public void configConstant(Constants constants) {
        PropKit.use("config.properties");
        constants.setBaseDownloadPath("/");
        // 开启对 jfinal web 项目组件 Controller、Interceptor、Validator 的注入
        constants.setInjectDependency(true);
        // 开启对超类的注入。不开启时可以在超类中通过 Aop.get(...) 进行注入
        constants.setInjectSuperClass(true);
        constants.setToSlf4jLogFactory();
        constants.setJsonFactory(new FastJsonFactory());
    }

    @Override
    public void configRoute(Routes routes) {
        routes.add(new Routes() {
            @Override
            public void config() {
                // 添加后台管理拦截器，将拦截在此方法中注册的所有 Controller
//                this.addInterceptor(new AdminAuthInterceptor());
//                this.addInterceptor(new PjaxInterceptor());

                this.setBaseViewPath("/_view");

                // 如果被扫描的包在 jar 文件之中，需要添加如下配置：
                // undertow.hotSwapClassPrefix = com.jfinal.club._admin.
                this.scan("com.jf.docsify.modules.");
            }
        });
    }

    @Override
    public void configEngine(Engine engine) {
        // 配置极速模式，性能提升 13%
        engine.setFastMode(true);
        // jfinal 4.9.02 新增配置：支持中文表达式、中文变量名、中文方法名、中文模板函数名
        engine.setChineseExpression(true);
    }

    @Override
    public void configPlugin(Plugins plugins) {
        plugins.add(new EhCachePlugin());
        DruidPlugin dp = createDruidPlugin();
        plugins.add(dp);
        ActiveRecordPlugin arp = new ActiveRecordPlugin(dp);
        /******** 在此添加数据库 表-Model 映射 *********/
        _MappingKit.mapping(arp);
        arp.setShowSql(true);
        // 添加到插件列表中
        plugins.add(arp);
    }

    public static DruidPlugin createDruidSqlitePlugin() {
        String url = PropKit.get("docsify.db.url");
        String dbFilePath = getSqliteDbFilePath(url);
        String jdbcUrl = "jdbc:sqlite:" + dbFilePath;
        String userName = PropKit.get("docsify.db.username");
        String password = PropKit.get("docsify.db.password");
        DruidPlugin dp = new DruidPlugin(jdbcUrl, userName, password);
        return dp;
    }

    public static String getSqliteDbFilePath(String dbFilePath) {
        String baseFolder = createDefaultDocFolder();
        if (StringUtils.isBlank(dbFilePath)) {
            dbFilePath = "jfDocsify.db";
        }
        boolean isAbsolutePath = false;
        boolean win = SystemUtil.isWin();
        boolean linux = SystemUtil.isLinux();
        if (win) {
            isAbsolutePath = dbFilePath.indexOf(":") != -1;
        } else if (linux) {
            isAbsolutePath = dbFilePath.startsWith("/");
        }
        if (!isAbsolutePath) {
            if (win) {
                dbFilePath = "\\" + dbFilePath;
                if (!dbFilePath.endsWith(".db")) {
                    dbFilePath = dbFilePath + "\\" + "jfDocsify.db";
                }
                dbFilePath = baseFolder + "\\db" + dbFilePath;
            } else if (linux) {
                dbFilePath = "/" + dbFilePath;
                if (!dbFilePath.endsWith(".db")) {
                    dbFilePath = dbFilePath + "/" + "jfDocsify.db";
                }
                dbFilePath = baseFolder + "/db" + dbFilePath;
            } else {
                DocsifyException.throwE("未知的操作系统" + SystemUtil.systemOs());
            }
        }
        File file = new File(dbFilePath);
        File parentFile = file.getParentFile();
        FileUtil.mkdirs(parentFile);
        return dbFilePath;
    }

    public static DruidPlugin createDruidMySqlPlugin() {
        String jdbcUrl = PropKit.get("docsify.db.url");
        String userName = PropKit.get("docsify.db.username");
        String password = PropKit.get("docsify.db.password");
        DruidPlugin dp = new DruidPlugin(jdbcUrl, userName, password);
        return dp;
    }

    public static DruidPlugin createDruidPlugin() {
        PropKit.use("config.properties");
        DruidPlugin dp = null;
        String dbType = PropKit.get("docsify.db.type");
        if (StringUtils.equals(dbType, "mysql")) {
            dp = createDruidMySqlPlugin();
        } else if (StringUtils.equals(dbType, "sqlite")) {
            dp = createDruidSqlitePlugin();
        }
        try {
            Boolean initEnable = PropKit.getBoolean("db.init.enable", false);
            if (initEnable) {
                DbInit.init(dbType);
                DbInit.saveDisabled("config.properties");
            }
        } catch (Exception e) {
            DocsifyException.throwE("初始化数据库异常", e);
        }
        return dp;
    }

    @Override
    public void configInterceptor(Interceptors interceptors) {
        interceptors.add(new ErrorInterceptor());
        interceptors.add(new AuthInterceptor());
    }

    @Override
    public void configHandler(Handlers handlers) {
        handlers.add(new UrlSkipHandler("^/git/(.*)", false));
        handlers.add(new MdUrlRewriteHandler());
    }

    @Override
    public void onStart() {
        super.onStart();
        initDefaultUser();
        createDefaultDocFolder();
    }

    private void initDefaultUser() {
        SysUser user = new SysUser();
        superAdminUserName = PropKit.get("app.init.username", "jfDocsify");
        AssertUtil.hasText(superAdminUserName, "请配置默认用户名");
        List<SysUser> sysUsers = user.find("select * from sys_user where user_name = ?", superAdminUserName);
        Integer userId;
        if (CollectionUtils.isEmpty(sysUsers)) {
            user.setUserName(superAdminUserName);
            user.setPassword(SecurityUtil.md5(HashKit.md5("1234")));
            user.save();
            userId = user.getId();
        } else {
            userId = sysUsers.get(0).getId();
        }
        Organization organization = new Organization();
        List<Organization> organizations = organization.find("select * from doc_organization where path = ?", superAdminUserName);
        if (CollectionUtils.isEmpty(organizations)) {
            organization.setOrganizationName("默认");
            organization.setPath(superAdminUserName);
            organization.setRemark("默认组织");
            organization.setUserId(userId);
            organization.save();
        }
    }

    /**
     * 创建默认文档存放目录
     * @return
     */
    public static String createDefaultDocFolder() {
        if (StringUtils.isNotBlank(defaultPath)) {
            return defaultPath;
        }
        boolean win = SystemUtil.isWin();
        boolean linux = SystemUtil.isLinux();
        String baseFolder = PropKit.use("config.properties").get("app.init.baseFolder");
        boolean isAbsolutePath = false;
        if (win) {
            isAbsolutePath = baseFolder.indexOf(":") != -1;
        } else if (linux) {
            isAbsolutePath = baseFolder.startsWith("/");
        }
        if (StringUtils.isNotBlank(baseFolder) && isAbsolutePath) {
            FileUtil.mkdirs(baseFolder);
            defaultPath = baseFolder;
            FileUtil.mkdirs(defaultPath + File.separator + gitDefaultFolderName);
            return defaultPath;
        }
        if (StringUtils.isNotBlank(baseFolder)) {
            if (win) {
                baseFolder = "\\" + baseFolder;
            } else if (linux) {
                baseFolder = "/" + baseFolder;
            }
        }
        String sysUserName = SystemUtil.sysUserName();
        if (win) {
            defaultPath = "\\C:\\Users\\" + sysUserName + "\\Documents\\jfDocsify" + baseFolder;
        } else if (linux) {
            defaultPath = "/home/" + sysUserName + "/Documents/jfDocsify" + baseFolder;
        } else {
            DocsifyException.throwE("未知的操作系统" + SystemUtil.systemOs());
        }
        FileUtil.mkdirs(defaultPath);
        FileUtil.mkdirs(defaultPath + File.separator + gitDefaultFolderName);
        return defaultPath;
    }
}